#include "synth.hpp"
#include <fstream>
#include <iostream>

#include <assert.h>
#include <math.h>
#include <sekai/common.h>
#include <sekai/mfcc.h>
#include <sndfile.h>
#include <stdlib.h> /* srand, rand */

#define TWOPI (2 * M_PI)
#define IMP_LENGTH_MAX (1024 * 8)

using namespace std;

extern std::string basedir;

double midi_freq(float m) {
  /* converts a MIDI note number to a frequency
     <http://en.wikipedia.org/wiki/MIDI_Tuning_Standard> */
  return 440.0 * pow(2, (double)(m - 69.0) / 12.0);
}



Synth::Synth() {

  VoiceDefESPEAK* def = new VoiceDefESPEAK("autobahn.pho");

  for (int i = 0; i < MAX_POLYPHONY; i++) {
    key[i] = 0;
    freq[i] = 0;
    voice[i] = new SynthRT();
    voice[i]->voicedef = def;
    voice[i]->impulse_response = new float[IMP_LENGTH_MAX];
    voice[i]->samplerate = 0;
  }

  
  
  
  

 
}

void Synth::init(int samplerate, int buffer_size) {
  this->samplerate = samplerate;
  this->buffer_size = buffer_size;
  for (int i = 0; i < MAX_POLYPHONY; i++) {
    voice[i]->samplerate = samplerate;
  }
}

Synth::~Synth() {}

void Synth::noteOn(int notenum, int velocity) {
  for (int i = 0; i < MAX_POLYPHONY; i++) {
    if (freq[i] == 0) {
      freq[i] = midi_freq(notenum + bend);
      key[i] = notenum;
      if (i > 0)
        voice[i]->setInputPositionSamples(voice[0]->inputPositionSamples());
      active_keys++;
      break;
    }
  }
}
void Synth::noteOff(int notenum) {
  for (int i = 0; i < MAX_POLYPHONY; i++) {
    if (key[i] == notenum) {
      freq[i] = 0;
      key[i] = 0;
      voice[i]->reset();
      voice[i]->setInputPositionSamples(0);
      active_keys--;
      break;
    }
  }
}

void Synth::controllerEvent(int a1, int a2) {
  if (a1 == 1) speed = 128 - a2;
}

void Synth::pitchBend(int a1, int a2) {
  float fract = 1.0 * (a2 * 128 + a1 - 8 * 1024) / (8 * 1024);
  bend = fract;
  for (int i = 0; i < MAX_POLYPHONY; i++) {
    if (freq[i]) freq[i] = midi_freq(key[i] + bend);
  }
}

void Synth::fill(float *buffer, int size) {
  for (int i = 0; i < size; i++) buffer[i] = 0;
  static int size2=size;

  for (int i = 0; i < MAX_POLYPHONY; i++) {
    if (key[i]) {
      float T0 = (samplerate / freq[i]);

      voice[i]->period = T0;
      voice[i]->enabled = true;
    }
    else
    {
      voice[i]->period = 10;
      voice[i]->enabled = false;
    }
  }

  float buffer_tmp[size];
  for (int i = 0; i < MAX_POLYPHONY; i++) {
      voice[i]->readData(buffer_tmp,size,size2);
      for (int j = 0; j < size; j++) buffer[j] += buffer_tmp[j];
  }
  
 
  if(active_keys) {
      for (int i = 0; i < size; i++) buffer[i] /= active_keys;
  }
}

static const int olabuffer_length=1024*8;
SynthRT::SynthRT() : VoiceSampler(olabuffer_length)
{
    
}
bool SynthRT::addOnePulse()
{
    if(enabled)
    {
       float factor = 0.25;
       float pos = inputPositionSamples() * factor / samplerate;
       voicedef->getImpulseResponse(pos,impulse_response,&impulse_response_length,0);
       printf("pos %f impulse_response_length %i\n",pos,impulse_response_length);
       hanningWindow(impulse_response,impulse_response_length);
       ola(impulse_response,impulse_response_length,period);
    }
    else
    {
        float dummy=0;
        ola(&dummy,1,10);
    }
    
    return true;
}
